using System;
using System.Collections;

namespace Tycho.Parser.Peg {
    public class SequenceProduction : Production {
        private IProduction[] Productions;

        public SequenceProduction (params IProduction[] productions) {
            Productions = productions;
        }

        /*
        protected override ParseResult ReallyParse (char[] source, int index, ParseContext context, string sourceString, ParseEnvironment parseEnvironment) {
            ParseResult result = null;
            foreach (var production in Productions) {
                result = production.Parse (source, index, context, sourceString, parseEnvironment);

                if (result == null) {
                    return null;
                }

                index = result.Index;
                context = result.Context;
            }
            return result;
        }
        */

        protected override Yield ReallyParse (char[] source, int index, ParseContext context, string sourceString, ParseEnvironment parseEnvironment, Func<ParseResult, Yield> continuation) {
            ParseResult result = null;
            IEnumerator productionsEnumerator = Productions.GetEnumerator();

            return ParseProduction(productionsEnumerator, result, source, index, parseEnvironment, context, sourceString, continuation);
        }

        private Yield ParseProduction (IEnumerator productionsEnumerator, ParseResult finalResult, char[] source,
                                       int index, ParseEnvironment parseEnvironment, ParseContext context,
                                       string sourceString, Func<ParseResult, Yield> continuation) {
            if (productionsEnumerator.MoveNext ()) {
                var production = (IProduction) productionsEnumerator.Current;
                return production.Parse (source, index, context,
                                         sourceString, parseEnvironment, result => {
                                             if (result == null) {
                                                 return () => continuation (null);
                                             }

                                             return
                                                 ParseProduction (
                                                     productionsEnumerator, result,
                                                     source, result.Index,
                                                     parseEnvironment, result.Context,
                                                     sourceString, continuation);
                                         });
            } else {
                return () => continuation (finalResult);
            }
        }
    }
}